package sf.r2dbc.sql;

import io.r2dbc.spi.Statement;
import sf.database.jdbc.sql.SQLParameter;
import sf.database.jdbc.type.AttributeConverterType;
import sf.database.jdbc.type.TypeHandler;
import sf.database.meta.ColumnMapping;
import sf.r2dbc.binding.BindMarker;
import sf.spring.util.CollectionUtils;
import sf.tools.ArrayUtils;
import sf.tools.StringUtils;

import javax.persistence.AttributeConverter;
import javax.persistence.EnumType;
import javax.persistence.TemporalType;
import java.util.ArrayList;
import java.util.List;

public class R2dbcSql {
    public static Statement fillSQLStatement(Statement statement, List<SQLParameter> paras) {
        if (!CollectionUtils.isEmpty(paras)) {
            for (int i = 0; i < paras.size(); i++) {
                SQLParameter p = paras.get(i);
                Class<?> clz = null;
                AttributeConverter<?, ?> attributeConverter = null;
                TypeHandler<?> typeHandler = null;
                TemporalType temporalType = null;
                EnumType enumType = null;
                ColumnMapping cm = p.getColumnMapping();
                if (cm != null) {
                    clz = cm.getClz();
                    typeHandler = cm.getHandler();
                    if (typeHandler.getClass() == AttributeConverterType.class) {
                        attributeConverter = ((AttributeConverterType) typeHandler).getAttributeConverter();
                    }
                    if (cm.getTemporal() != null) {
                        temporalType = cm.getTemporal().value();
                    }
                    if (cm.getEnumerated() != null) {
                        enumType = cm.getEnumerated().value();
                    }
                } else if (p.getJavaType() != null) {
                    clz = p.getJavaType();
                } else {
                    clz = Object.class;
                }
                if (StringUtils.isNotBlank(p.getExpression())) {
                    statement = R2dbcConvertUtils.set(statement, p.getValue(), p.getExpression(), clz, attributeConverter, temporalType, enumType);
                } else {
                    statement = R2dbcConvertUtils.set(statement, p.getValue(), i, clz, attributeConverter, temporalType, enumType);
                }
            }
        }
        return statement;
    }

    public static void fillSQLStatement(Statement target, List<BindMarker> bindMarkerList, List<SQLParameter> paras) {
        if (!CollectionUtils.isEmpty(paras)) {
            for (int i = 0; i < paras.size(); i++) {
                SQLParameter p = paras.get(i);
                Class<?> clz = null;
                AttributeConverter<?, ?> attributeConverter = null;
                TypeHandler<?> typeHandler = null;
                TemporalType temporalType = null;
                EnumType enumType = null;
                ColumnMapping cm = p.getColumnMapping();
                if (cm != null) {
                    clz = cm.getClz();
                    typeHandler = cm.getHandler();
                    if (typeHandler.getClass() == AttributeConverterType.class) {
                        attributeConverter = ((AttributeConverterType) typeHandler).getAttributeConverter();
                    }
                    if (cm.getTemporal() != null) {
                        temporalType = cm.getTemporal().value();
                    }
                    if (cm.getEnumerated() != null) {
                        enumType = cm.getEnumerated().value();
                    }
                } else if (p.getJavaType() != null) {
                    clz = p.getJavaType();
                } else {
                    clz = Object.class;
                }
                R2dbcConvertUtils.set(bindMarkerList.get(i), target, p.getValue(), clz, attributeConverter, temporalType, enumType);
            }
        }
    }

    public static void fillSQLStatement(Statement target, List<BindMarker> bindMarkerList, Object... paras) {
        if (!ArrayUtils.isEmpty(paras)) {
            for (int i = 0; i < paras.length; i++) {
                Object value = paras[i];
                Class<?> clz = null;
                if (value != null) {
                    clz = value.getClass();
                } else {
                    clz = Object.class;
                }
                R2dbcConvertUtils.set(bindMarkerList.get(i), target, value, clz, null, null, null);
            }
        }
    }

    /**
     * 单一对象赋值
     * @param bindTarget
     * @param bindMarker
     * @param value
     * @param cm
     */
    public static void fillSQLStatement(Statement bindTarget, BindMarker bindMarker, Object value, ColumnMapping cm) {
        Class<?> clz = null;
        AttributeConverter<?, ?> attributeConverter = null;
        TypeHandler<?> typeHandler = null;
        TemporalType temporalType = null;
        EnumType enumType = null;
        if (cm != null) {
            clz = cm.getClz();
            typeHandler = cm.getHandler();
            if (typeHandler.getClass() == AttributeConverterType.class) {
                attributeConverter = ((AttributeConverterType) typeHandler).getAttributeConverter();
            }
            if (cm.getTemporal() != null) {
                temporalType = cm.getTemporal().value();
            }
            if (cm.getEnumerated() != null) {
                enumType = cm.getEnumerated().value();
            }
        } else if (value != null) {
            clz = value.getClass();
        } else {
            clz = Object.class;
        }
        R2dbcConvertUtils.set(bindMarker, bindTarget, value, clz, attributeConverter, temporalType, enumType);
    }

    public static List<SQLParameter> getParameterList(Object[] parameters) {
        List<SQLParameter> list = new ArrayList<>();
        for (Object o : parameters) {
            SQLParameter p = new SQLParameter();
            p.setValue(o);
            list.add(p);
        }
        return list;
    }
}
